const scrapy = require('node-scrapy');
const fs = require('fs');
module.exports = class extends think.Service {
    async scrapyHome() {
        const model = {
            urls: [
                '.n-rcmd .m-cvrlst li',
                {
                    url: '.dec a => href',
                },
            ],
        };
        const res = await think.ajax({
            api: think.api.scrapyMusic163,
            data: {}
        });
        return new Promise(async (resolve) => {
            let {urls} = scrapy.extract(res, model);
            for (let item of urls) {
                const id = item.url.split('=')[1];
                this.model('task').query('BEGIN');
                await this.model('task').thenAdd({
                    music_id: id,
                    type: 'home',
                    status: 0,
                    url: `https://music.163.com${item.url}`,
                }, {
                    music_id: id,
                }).catch(() => {
                    /*this.model('task').query('rollback');*/
                });
                this.model('task').query('COMMIT');
            }
            resolve(urls)
        });
    }


    async scrapyCms() {
        let play_replay_list = await this.model('play_replay_fix').where({
            status: 0
        }).limit(100).select();
        /* play_replay_list = play_replay_list.map((item: any) => {
             item.status = 1;
             return item
         });
         await this.model('play_replay_fix').updateMany(play_replay_list);*/
        const model = {
            players: [
                '.box .container .block',
                {
                    name: '.user_name => $textContent',
                    score: '.user_head .score .score_2 => $textContent',
                },
            ],
        };
        let updateList: any = [];
        let finished = false;
        new Promise((resolve) => {
            resolve()
        }).then(() => {
            let i = 0;
            for (let play_replay of play_replay_list) {
                //异步操作
                think.ajax({
                    api: {
                        url: play_replay.history_link,
                        html: true,
                        method: 'get',
                    },
                    data: {}
                }).then((res: any) => {
                    let {players} = scrapy.extract(res, model);
                    let hasK = false;
                    let all = true;
                    i++;
                    if (i === play_replay_list.length - 1) {
                        finished = true
                    }
                    if (!players) {
                        return;
                    }
                    players = players.map((item: any) => {
                        item.name = item.name.replace(/\s/g, '');
                        item.score = item.score.replace(/\s/g, '').replace('+', '');
                        if (item.score.toLowerCase().indexOf('k') > -1) {
                            hasK = true;
                        }
                        if (!(play_replay.play1_name === item.name || play_replay.play2_name === item.name || play_replay.play3_name === item.name)) {
                            all = false;
                        }
                        return item
                    });

                    players.forEach((player: any, index: any) => {
                        if (hasK) {
                            play_replay[`play${index + 1}_all_win_score`] = player.score;
                            play_replay[`play${index + 1}_name`] = player.name;
                        } else {
                            if (play_replay.play1_name === player.name) {
                                play_replay.play1_all_win_score = player.score;
                            }
                            if (play_replay.play2_name === player.name) {
                                play_replay.play2_all_win_score = player.score;
                            }
                            if (play_replay.play3_name === player.name) {
                                play_replay.play3_all_win_score = player.score;
                            }
                        }

                    });

                    if (hasK) {
                        if (all) {
                            updateList.push({
                                id: play_replay.id,
                                play1_all_win_score: play_replay.play1_all_win_score,
                                play2_all_win_score: play_replay.play2_all_win_score,
                                play3_all_win_score: play_replay.play3_all_win_score,
                                status: 3,
                            })
                        } else {
                            updateList.push({
                                id: play_replay.id,
                                play1_all_win_score: play_replay.play1_all_win_score,
                                play2_all_win_score: play_replay.play2_all_win_score,
                                play3_all_win_score: play_replay.play3_all_win_score,
                                status: -3,
                            })
                        }
                    } else {
                        updateList.push({
                            id: play_replay.id,
                            play1_all_win_score: play_replay.play1_all_win_score,
                            play2_all_win_score: play_replay.play2_all_win_score,
                            play3_all_win_score: play_replay.play3_all_win_score,
                            status: all ? 2 : -2,
                        })
                    }
                    /*think.logger.info(play_replay);*/
                });

            }

            return new Promise((resolve) => {
                const interval = setInterval(() => {
                    if (finished) {
                        think.logger.info(updateList.length);
                        clearInterval(interval);
                        resolve();
                    }
                }, 1)
            })
        })
            .then(() => {
                this.model('play_replay_fix').updateMany(updateList);
                console.log("All Promise finished");
                if (updateList.length > 0) {
                    this.scrapyCms();
                }
            })


    }

    async scrapyDetail() {
        const model = {
            urls: [
                '.f-hide li',
                {
                    url: 'a => href',
                    name: 'a => $textContent',
                },
            ],
        };
        const urlList = await this.model('task').where({
            status: ['in', '0,-1']
        }).select();
        for (let item of urlList) {
            const res = await think.ajax({
                api: {
                    url: `${item.url}`,
                    html: true,
                    method: 'get',
                },
                data: {}
            });
            let {urls} = scrapy.extract(res, model);
            for (let _item of urls) {
                const id = _item.url.split('=')[1];
                const res = await think.ajax({
                    api: think.api.downloadMusic,
                    data: {
                        id: `${id}.mp3`
                    }
                });
                const lyric = await think.ajax({
                    api: think.api.downloadLyric,
                    data: {
                        id: `${id}`
                    }
                });
                console.error(res.length);

                if (res.length > 102400) {
                    const musicPath = think.ROOT_PATH + `/temp/mp3/${_item.name}.mp3`;
                    await this.downloadMusic({res, filepath: musicPath});
                    const lyricPath = think.ROOT_PATH + `/temp/lyric/${_item.name}.txt`;
                    if (lyric.lrc) {
                        const lyricTxt = lyric.lrc.lyric;
                        const buffer = new Buffer(lyricTxt);
                        await this.downloadMusic({res: buffer, filepath: lyricPath, encoding: 'utf8'})
                    }

                }
            }
        }
    }

    /**
     * 下载excel
     * @param res
     * @param filepath
     * @returns {Promise<*>}
     */
    async downloadMusic({res, filepath, encoding}: any) {
        const flag = await this.writeFile(res, filepath, encoding);
        if (flag) {
            return new Promise((resolve) => {
                resolve(flag);
            });
        }
        else {
            return this.downloadMusic({res, filepath,});
        }
    }

    /**
     * 读取路径信息
     * @param {string} path 路径
     */
    getStat(path: any) {
        return new Promise((resolve, reject) => {
            fs.stat(path, (err: any, stats: any) => {
                if (err) {
                    resolve(false);
                } else {
                    resolve(stats);
                }
            });
        });
    }

    /**
     * 创建路径
     * @param {string} dir 路径
     */
    mkdir(dir: any) {
        return new Promise((resolve, reject) => {
            fs.mkdir((dir: any, err: any) => {
                if (err) {
                    resolve(false);
                } else {
                    resolve(true);
                }
            });
        });
    }

    /**
     * 路径是否存在，不存在则创建
     * @param {string} dir 路径
     */
    async dirExists(dir: any) {
        let isExists: any = await this.getStat(dir);
        //如果该路径且不是文件，返回true
        if (isExists && isExists.isDirectory()) {
            return true;
        } else if (isExists) {     //如果该路径存在但是文件，返回false
            return false;
        }
        //如果该路径不存在
        let tempDir = path.parse(dir).dir;      //拿到上级路径
        //递归判断，如果上级目录也不存在，则会代码会在此处继续循环执行，直到目录存在
        let status = await this.dirExists(tempDir);
        let mkdirStatus;
        if (status) {
            mkdirStatus = await this.mkdir(dir);
        }
        return mkdirStatus;
    }

    /**
     * 写文件
     * @param res
     * @param filepath
     * @returns {Promise<bluebird>}
     */
    async writeFile(res: any, filepath: any, encoding = 'binary') {
        const filepaths = filepath.split('/');
        filepaths.pop();
        const dir = filepaths.join('/')
        await this.dirExists(dir);
        return new Promise((resolve) => {
            fs.writeFile(filepath, res, encoding, function (err: any) {
                if (!err) {
                    resolve(filepath);
                }
                else {
                    resolve(null);
                }
            });
        });
    }

};
